package com.xjf.security.config;

import com.xjf.security.handler.FailureAuthenticationHandler;
import com.xjf.security.handler.SuccessAuthenticationHandler;
import com.xjf.security.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

/**
 * SpringSecurity 的配置
 *
 * @author xjf
 * @date 2020/2/20 11:23
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 注入自定义的成功处理器、失败处理器、认证
     */
    @Autowired
    private UserService userService;
    @Autowired
    private SuccessAuthenticationHandler successAuthenticationHandler;
    @Autowired
    private FailureAuthenticationHandler failureAuthenticationHandler;

    @Autowired
    private PersistentTokenRepository persistentTokenRepository;

    /**
     * 注入认证管理器 bean
     *
     * @return
     * @throws Exception
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /**
     * 将 userService 放入 AuthenticationManagerBuilder 中
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .userDetailsService(userService)
//                .passwordEncoder(new BCryptPasswordEncoder());
                // 自定义实现密码加密算法
                .passwordEncoder(new PasswordEncoder() {
                    // 对密码进行加密，返回加密后的字符串
                    @Override
                    public String encode(CharSequence rawPassword) {
                        System.err.println("加密密码：" + rawPassword);
                        // 此处测试没有加密
                        return rawPassword.toString();
                    }

                    // 对加密后的字符串进行验证匹配
                    @Override
                    public boolean matches(CharSequence rawPassword, String encodedPassword) {

                        boolean equals = encodedPassword.equals(rawPassword.toString());
                        System.out.println("密码是否正确：" + equals);
                        return equals;
                    }
                });
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // Spring Security 支持两种不同的认证方式: 1. from 表单认证。 2. HttpBasic 认证。
        // 此处测试是表单认证
        http.formLogin()
                // 登录的 url
                .loginPage("/login")
                // 自定义登录路径
                .loginProcessingUrl("/authentication/form")
                // 自定义登录成功处理
                .successHandler(successAuthenticationHandler)
                // 自定义登录失败处理
                .failureHandler(failureAuthenticationHandler)
                .and()
                .logout()
                // 注销的 url
                .logoutUrl("/logout")
                .and()
                // 对请求授权
                .authorizeRequests()
                // 对如下的路径不认证，直接放行
                .antMatchers("/login", "/sms/**", "/authentication/form").permitAll()
                // 任何请求
                .anyRequest()
                // 都需要身份认证
                .authenticated()
                .and()
                // 添加 "记住我" 功能
                .rememberMe()
                // 修改 cookie 的属性值，默认是 remember-me
//                .rememberMeCookieName("remember")
                // 使用数据库存储方式实现 "remember-me" 功能
                .tokenRepository(persistentTokenRepository)
                .tokenValiditySeconds(3600)
                .and()
                // 禁用跨站攻击
                .csrf().disable();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        // 设置忽略文件夹（不拦截），对静态资源放行
        web.ignoring().antMatchers("/css/**", "/js/**");
    }
}
